#include "TcpConnection.h"

namespace mpgl_engine{ namespace application{ namespace net {
	
	void TcpConnection::Update()
	{

	}

	void TcpConnection::SendData(bool clear)
	{
		// If we are not currently writing, and have data
		// ready to send out.
		if ((m_connectionState & TcpConnectionState::WRITING) !=
			TcpConnectionState::WRITING &&
			(m_connectionState & ~TcpConnectionState::OUTPUT_READY) !=
			~TcpConnectionState::OUTPUT_READY)
		{
			//Set writing input flag
			m_connectionState =
				(m_connectionState | TcpConnectionState::WRITING);

			//Async write request
			boost::asio::async_write(
				//Socket to write to
				m_socket,
				//Buffer to write to socket
				boost::asio::buffer( 
					//
					m_outData->AccessDataBuffer(),
					//
					m_outData->GetBufferIndex()
				), 
				//Function to call when completed
				boost::bind(
					//reference to the handler function
					&TcpConnection::HandleWrite,
					//pointer to the class instance
					this,
					//boost error placeholder
					boost::asio::placeholders::error,
					//boost bytes transfered placeholder
					boost::asio::placeholders::bytes_transferred
				)
			);
		}
	}
	void TcpConnection::HandleWrite(
		const boost::system::error_code& error, size_t size)
	{
		if (!error)
		{

		}
		else
		{
			//Remove the WRITING flag.
			m_connectionState =
				(m_connectionState & ~TcpConnectionState::WRITING);

			//Check if we need to remove the OUTPUT_READY flag
			//** todo
		}
	}

	void TcpConnection::ReadData(bool concat)
	{
		// If we are not currently reading, or have input data
		// read and ready to parse.
		if ((m_connectionState & TcpConnectionState::READING) != 
				TcpConnectionState::READING &&
			(m_connectionState & TcpConnectionState::INPUT_READY) !=
				TcpConnectionState::INPUT_READY)
		{
			//Set reading input flag
			m_connectionState = 
				(m_connectionState | TcpConnectionState::READING);

			//Async read request
			boost::asio::async_read(
				//Socket to write to
				m_socket,
				//Buffer to write to socket
				boost::asio::buffer(
					//
					m_inData->AccessDataBuffer(),
					//Length of buffers available space
					m_inData->GetBufferLength()
				),
				//Function to call when completed
				boost::bind(
					//reference to the handler function
					&TcpConnection::HandleRead,
					//pointer to the class instance
					this,
					//boost error placeholder
					boost::asio::placeholders::error,
					//boost bytes transfered placeholder
					boost::asio::placeholders::bytes_transferred
				)
			);
		}
	}
	void TcpConnection::HandleRead(
		const boost::system::error_code& error, size_t sizeRead)
	{
		/*--------------
		* Check number of bytes read against packet size stated
		* in the packet.
		---------------*/

		//Check for boost errors or empty data
		if (!error && m_inData->GetBufferLength() > 0)
		{
			//Grab first two digits for parsing total packet
			// size.
			char sizeRaw[2] = {
				m_inData->GetDataBuffer()[0],
				m_inData->GetDataBuffer()[1] };
			//Parse total packet size.
			unsigned short size = 
				(unsigned short)strtoul(sizeRaw, NULL, 0);

			// If size read is correct
			if (sizeRead == size)
			{
				// set  m_connectionState to INPUT_READY
				m_connectionState =
					( m_connectionState & 
					 ~TcpConnectionState::READING &
					  TcpConnectionState::INPUT_READY );

				// set input data ready flag
				m_inData++;
			}

			/*--------------
			* Error: On size mismatch
			---------------*/
			else
			{
				// Remove READING flag, and don't set the INPUT_READY
				// flag.
				m_connectionState =
					( m_connectionState & 
					  ~TcpConnectionState::READING &
					  ~TcpConnectionState::INPUT_READY );
			}
		}
		/*--------------
		* Error: On empty input data buffer
		---------------*/
		else if (m_inData->GetBufferLength() < 0)
		{
			// Remove READING flag, and don't set the INPUT_READY
			// flag.
			m_connectionState =
				(m_connectionState &
				~TcpConnectionState::READING &
				~TcpConnectionState::INPUT_READY);
		}
		/*--------------
		* Error: On boost error_code error
		---------------*/
		else if ( error )
		{
			// Remove READING flag, and don't set the INPUT_READY
			// flag.
			m_connectionState =
				( m_connectionState & 
				~TcpConnectionState::READING &
				~TcpConnectionState::INPUT_READY );
		}
		/*--------------
		* Error: On other error
		---------------*/
		else
		{
			// Remove READING flag, and don't set the INPUT_READY
			// flag.
			m_connectionState =
				(m_connectionState &
				~TcpConnectionState::READING &
				~TcpConnectionState::INPUT_READY);
		}
	}

}}}